/*
 #
 #  Files       : Vecteur.h
 #                ( C++ header file )
 #
 #  Description : The SmallMatrix Library
 #                ( http://code.google.com/p/smallmatrix )
 #
 #  Copyright   : Olivier Juan
 #                ( http://www.mas.ecp.fr/vision/Personnel/juan/ )
 #
 #  License     : CeCILL-C
 #                ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 #
 #  This software is governed by the CeCILL-C license under French law and
 #  abiding by the rules of distribution of free software.  You can  use,
 #  modify and or redistribute the software under the terms of the CeCILL-C
 #  license as circulated by CEA, CNRS and INRIA at the following URL
 #  "http://www.cecill.info".
 #
 #  As a counterpart to the access to the source code and  rights to copy,
 #  modify and redistribute granted by the license, users are provided only
 #  with a limited warranty  and the software's author,  the holder of the
 #  economic rights,  and the successive licensors  have only  limited
 #  liability.
 #
 #  In this respect, the user's attention is drawn to the risks associated
 #  with loading,  using,  modifying and/or developing or reproducing the
 #  software by the user in light of its specific status of free software,
 #  that may mean  that it is complicated to manipulate,  and  that  also
 #  therefore means  that it is reserved for developers  and  experienced
 #  professionals having in-depth computer knowledge. Users are therefore
 #  encouraged to load and test the software's suitability as regards their
 #  requirements in conditions enabling the security of their systems and/or
 #  data to be ensured and,  more generally, to use and operate it in the
 #  same conditions as regards security.
 #
 #  The fact that you are presently reading this means that you have had
 #  knowledge of the CeCILL-C license and that you accept its terms.
 #
*/

#ifndef _VECTEUR_H
#define _VECTEUR_H
#include "SmallMatrix.h"


//////////////////////////////////////////////////////////////////////
//
// - JUAN Olivier 15/03/2005 --> Release Candidate 2
//                           --> Joyeuse Paques (bientot)
//
//////////////////////////////////////////////////////////////////////


NAMESPACE_BEGIN(SmallMatrix)

template <int M> class Vecteur : public Matrix_Base<Vecteur<M> >
{
private:
	typedef Matrix_Base<Vecteur<M> > Base;
public:
	template <int IdxR, int IdxC>
		reel& Access() {
			STATIC_ASSERT((IdxR<M)&&(IdxR>=0));
			STATIC_ASSERT(IdxC==0);
			return Base::template TabAccess<IdxR>();
		}
	template <int IdxR, int IdxC>
		const reel& Access() const {
			STATIC_ASSERT((IdxR<M)&&(IdxR>=0));
			STATIC_ASSERT(IdxC==0);
			return Base::template TabAccess<IdxR>();
		}
public:
	INLINE Vecteur(): Base(){};
	INLINE Vecteur(const reel tab[Base::SIZE]) : Base(tab){}
	template <typename TT> INLINE Vecteur(const TT& copy) : Base(copy){}
	//template <typename TT> INLINE Vecteur(const Matrix_Base<TT>& copy) : Base(copy){}
	INLINE Vecteur(const Vecteur<M>& copy) : Base(copy){}
	INLINE Vecteur(const reel &v) : Base(v) {}									// Pour tout M
	INLINE Vecteur(const reel &x,const reel &y);								// M=2 seulement
	INLINE Vecteur(const reel &x,const reel &y,const reel &z);					// M=3
	INLINE Vecteur(const reel &x,const reel &y,const reel &z,const reel &t);	// M=4
	template <typename TT> INLINE Vecteur<M>& operator=(const Matrix_Base<TT>& copy) {
		Base& ref=*this; 
		return ref = copy;
	}
	template <typename TT> INLINE Vecteur<M>& operator=(const TT& copy) {
		Base& ref=*this;
		return ref = copy;
	}
	INLINE Vecteur<M>& operator=(const Vecteur<M>& copy) {
		Base& ref=*this;
		return ref = copy;
	}
	INLINE reel& operator()(const int& idx,const int& null=0);
	INLINE const reel& operator()(const int& idx,const int& null=0)const;
	//template <typename T1,typename T2> INLINE Vecteur<M>& prod(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2);
	//template <typename T1,typename T2> INLINE Vecteur<M>& add(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2);
	//template <typename T1,typename T2> INLINE Vecteur<M>& subst(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2);
	//template <typename T1> INLINE Vecteur<M>& add(const Matrix_Base<T1>& M1);
	//template <typename T1> INLINE Vecteur<M>& subst(const Matrix_Base<T1>& M1);
	//template <typename T1> INLINE Vecteur<M>& mult(const Matrix_Base<T1>& M1);
	//template <typename T1> INLINE Vecteur<M>& div(const Matrix_Base<T1>& M1);
	//INLINE reel dot(const Vecteur<M>& Two)const;
	//template <int P> INLINE Matrix<M,P> outer_product(const Vecteur<P>& Two)const;
	//INLINE SquareMatrix<M> outer_product(const Vecteur<M>& Two)const;
	INLINE Vecteur<M> operator^(const Vecteur<M>&v) const;
	INLINE bool operator<(const Vecteur<M>& test)const;
	INLINE Vecteur<M>& normalize();
};

template <> 
INLINE Vecteur<2>::Vecteur(const reel &x,const reel &y):Matrix_Base<Vecteur<2> >(){
	Vecteur<2>& ref = *this;
	ref.Access<0,0>()=x;ref.Access<1,0>()=y;
}

template <> 
INLINE Vecteur<3>::Vecteur(const reel &x,const reel &y,const reel &z):Matrix_Base<Vecteur<3> >(){
	Vecteur<3>& ref = *this;
	ref.Access<0,0>()=x;ref.Access<1,0>()=y;ref.Access<2,0>()=z;
}

template <> 
INLINE Vecteur<4>::Vecteur(const reel &x,const reel &y,const reel &z,const reel &t):Matrix_Base<Vecteur<4> >(){
	Vecteur<4>& ref = *this;
	ref.Access<0,0>()=x;ref.Access<1,0>()=y;ref.Access<2,0>()=z;ref.Access<3,0>()=t;
}

#pragma warning( disable : 4100)
//! Read/Write Accessor
template <int M> INLINE reel& Vecteur<M>::operator ()(const int& idx,const int& null)
{
	assert((idx>=0)&&(idx<M)&&(null==0));
	Vecteur<M>& ref = *this;
	return ref[idx];
}
//! Read Only Accessor
template <int M> INLINE const reel& Vecteur<M>::operator ()(const int& idx,const int& null)const
{
	assert((idx>=0)&&(idx<M)&&(null==0));
	const Vecteur<M>& ref = *this;
	return ref[idx];
}
#pragma warning( default : 4100)

////! Matrix-Matrix Product in which the result is a Vecteur
//template <int M> template <typename T1,typename T2> INLINE Vecteur<M>& Vecteur<M>::prod(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2) {
//	Vecteur<M>& ref = *this;
//	for (int i=0;i<M;i++)
//		for (int k=0;k<T2::ROW;k++)
//			ref(i,0)+=M1(i,k)*M2(k,0);
//	return ref;
//}
////! Matrix-Matrix Sum in which the result is a Vecteur
//template <int M> template <typename T1,typename T2> INLINE Vecteur<M>& Vecteur<M>::add(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++)
//		ref(i,0)=M1(i,0)+M2(i,0);
//	return ref;
//}
////! Matrix-Matrix Substract in which the result is a Vecteur
//template <int M> template <typename T1,typename T2> INLINE Vecteur<M>& Vecteur<M>::subst(const Matrix_Base<T1>& M1,const Matrix_Base<T2>& M2) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++)
//		ref(i,0)=M1(i,0)-M2(i,0);
//	return ref;
//}
////! Matrix-Matrix Sum in which the result is a Vecteur
//template <int M> template <typename T1> INLINE Vecteur<M>& Vecteur<M>::add(const Matrix_Base<T1>& M1) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++)
//		ref(i,0)+=M1(i,0);
//	return ref;
//}
////! Matrix-Matrix Substract in which the result is a Vecteur
//template <int M> template <typename T1> INLINE Vecteur<M>& Vecteur<M>::subst(const Matrix_Base<T1>& M1) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++)
//		ref(i,0)-=M1(i,0);
//	return ref;
//}
//template <int M> template <typename T1> INLINE Vecteur<M>& Vecteur<M>::mult(const Matrix_Base<T1>& M1) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++)
//		ref(i,0)*=M1(i,0);
//	return ref;
//}
//template <int M> template <typename T1> INLINE Vecteur<M>& Vecteur<M>::div(const Matrix_Base<T1>& M1) {
//	Vecteur<M>& ref=*this;
//	for (int i=0;i<M;i++) {
//		assert(M1(i,0)!=0);
//		ref(i,0)/=M1(i,0);
//	}
//	return ref;
//}
////! Inner Product with the Vecteur \a Two
//template <int M> INLINE reel Vecteur<M>::dot(const Vecteur<M> &Two)const
//{
//	const Vecteur<M>& ref=*this;
//	return ref.Access<M-1,0>()*Two.Access<M-1,0>()+(*((const Vecteur<M-1>*)(this))).dot(*((const Vecteur<M-1>*)(&Two)));
//}
//template <> INLINE reel Vecteur<1>::dot(const Vecteur<1> &Two)const
//{
//	const Vecteur<1>& ref=*this;
//	return ref.Access<0,0>()*Two.Access<0,0>();
//}
////! Outer Product (*this) * Two'
//template <int M> template <int P> INLINE Matrix<M,P> Vecteur<M>::outer_product(const Vecteur<P> &Two)const
//{
//	const Vecteur<M>& ref=*this;
//	Matrix<M,P> A;
//	for (int i=0; i<M; i++)
//		for (int j=0; j<P; j++)
//			A(i,j)=ref(i)*Two(j);
//	return A;
//}
//template <int M> INLINE SquareMatrix<M> Vecteur<M>::outer_product(const Vecteur<M> &Two)const
//{
//	const Vecteur<M>& ref=*this;
//	SquareMatrix<M> A;
//	for (int i=0; i<M; i++)
//		for (int j=0; j<M; j++)
//			A(i,j)=ref(i)*Two(j);
//	return A;
//}
template <int M> INLINE bool Vecteur<M>::operator<(const Vecteur<M>& test)const
{
	const Vecteur<M>& ref=*this;
	bool res=true;
	int i=0;
	while((res)&&(i<M))
	{
		res=(ref[i]==test[i]);
		i++;
	}
	i--;
	return (res?false:(ref[i]<test[i]));
}
template <>
INLINE Vecteur<3> Vecteur<3>::operator^(const Vecteur<3>&v) const {
	const Vecteur<3>& ref = *this;
	return Vecteur<3>(ref[1]*v[2]-ref[2]*v[1], -ref[0]*v[2]+ref[2]*v[0], ref[0]*v[1]-ref[1]*v[0]);
}
template <int M>
Vecteur<M>& Vecteur<M>::normalize() 
{
	return ((*this) /= Base::norm());
}


NAMESPACE_END

#endif
